﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ConeManager : MonoBehaviour
{
    [SerializeField]               private Camera           m_Camera;
    [SerializeField]               private List<Cone>       m_Cones;
    [SerializeField, Range(1, 10)] private int              m_ConeLevel = 1;

    [SerializeField] private MonoSDivisionManager m_MonoSDivisionManager;
    [SerializeField] private float m_Aspect;
    [SerializeField] private bool  m_IsOrthographic;
    [SerializeField] private Transform m_TestTrans;

    private Plane[] m_Plane;

    private void Awake()
    {
        this.m_Aspect = (float) Screen.width / (float) Screen.height;
        this.m_Camera = this.GetComponent<Camera>();
        this.ConeGrading();
        SDivisionManager.Instance.SceneTrees.AddRange(this.m_MonoSDivisionManager.SceneTrees);
        SDivisionManager.Instance.Refresh();
    }

    private void Update()
    {
        this.InitlizeCone();
    }

    //视锥体分级。
    private void ConeGrading()
    {
        float avgFar = (this.m_Camera.farClipPlane) / this.m_ConeLevel;
        Cone  cone   = new Cone(this.m_Camera.nearClipPlane, avgFar, this.m_Camera.fieldOfView);
        cone.RenderCamera = this.m_Camera;
        cone.InityCone(this.m_Camera.aspect);
        this.m_Cones.Add(cone);
        for (int i = 1; i < this.m_ConeLevel; i++)
        {
            Cone newCone = new Cone(cone.Far, cone.Far + avgFar, this.m_Camera.fieldOfView);
            newCone.RenderCamera = this.m_Camera;
            newCone.InityCone(this.m_Camera.aspect);
            this.m_Cones.Add(newCone);
            cone = newCone;
        }
    }

    //初始化视锥体
    private void InitlizeCone()
    {
        if (this.m_Camera == null)
        {
            Debug.LogWarning("Render Camera Is null");
            return;
        }

        for (int i = 0; i < this.m_Cones.Count; i++)
        {
            this.m_Cones[i].InityCone(this.m_Camera.aspect);
        }

        this.m_Plane = GeometryUtility.CalculateFrustumPlanes(this.m_Camera);
        
        if (SDivisionManager.Instance.SceneTrees != null &&
            SDivisionManager.Instance.SceneTrees.Count > 0)
        {
            for (int i = 0; i < SDivisionManager.Instance.SceneTrees.Count; i++)
            {
                SceneTree stree = SDivisionManager.Instance.SceneTrees[i];
                this.CheckTreeBounds(stree);
            }
        }

        if (SDivisionManager.Instance.SceneTreesWhiteList != null &&
            SDivisionManager.Instance.SceneTreesWhiteList.Count > 0)
        {
            for (int i = 0; i < SDivisionManager.Instance.SceneTreesWhiteList.Count; i++)
            {
                SceneTree stree = SDivisionManager.Instance.SceneTreesWhiteList[i];
                for (int j = 0; j < stree.SceneObjects.Count; j++)
                {
                    SceneObject sobject = stree.SceneObjects[j];
                    bool state = GeometryUtility.TestPlanesAABB(this.m_Plane, sobject.Bounds);
                    if (sobject.Renderer)
                        sobject.Renderer.enabled = state;
                }
            }
        }
    }

    private void CheckTreeBounds(SceneTree stree)
    {
        if (stree.SceneTreeMainNode != null)
        {
            bool state = GeometryUtility.TestPlanesAABB(this.m_Plane, stree.SceneTreeMainNode.Bounds);
            if (state)
            {
                SDivisionManager.Instance.AddSceneTreesWhiteList(stree);
                SDivisionManager.Instance.RemoveSceneTreesGreyList(stree);
                stree.Initlize(stree.DivTreeType);
            }
            else
            {
                SDivisionManager.Instance.AddSceneTreesGreyList(stree);
                SDivisionManager.Instance.RemoveSceneTreesWhiteList(stree);
                stree.Clear();
            }
        }
    }

    private void OnDrawGizmos()
    {
        if (this.m_Camera == null) return;
        this.m_Cones.ForEach((item) => { item.DebugDrawCone(this.transform.position, this.transform.rotation); });
    }
}